import 'dart:async';
import 'dart:collection';

import 'package:flutter/gestures.dart';
import 'package:flutter/rendering.dart';
import 'dart:ui' as ui;

import 'package:flutter/widgets.dart';

// ignore: constant_identifier_names
const double SCREEN_WIDTH = 360;

class InnerWidgetsFlutterBinding extends WidgetsFlutterBinding {
  static WidgetsBinding ensureInitialized() {
    //if (WidgetsBinding.instance == null)
    InnerWidgetsFlutterBinding();
    return WidgetsBinding.instance;
  }

  double get adapterRatio {
    // View.of(_context).physicalSize.width;
    return platformDispatcher.implicitView!.physicalSize.width / SCREEN_WIDTH;
  }

  @override
  ViewConfiguration createViewConfiguration() {
    return ViewConfiguration(
      size: platformDispatcher.implicitView!.physicalSize / adapterRatio,
      devicePixelRatio: adapterRatio,
    );
  }

  void runMyApp(Widget app){
    runApp(app);
  }

  /// wrap [GestureBinding _handlePointerDataPacket]
  /// replace the [PixelRatio]
  @override
  void initInstances() {
    super.initInstances();
    platformDispatcher.onPointerDataPacket = _handlePointerDataPacket;
  }

  @override
  void unlocked() {
    super.unlocked();
    _flushPointerEventQueue();
  }

  final Queue<PointerEvent> _pendingPointerEvents = Queue<PointerEvent>();

  void _handlePointerDataPacket(ui.PointerDataPacket packet) {
    _pendingPointerEvents.addAll(PointerEventConverter.expand(
        packet.data,
        // 适配事件的转换比率,采用我们修改的
        _devicePixelRatioForView
        ));
    if (!locked) _flushPointerEventQueue();
  }

  double? _devicePixelRatioForView(int viewId) {
    return platformDispatcher.view(id: viewId)?.devicePixelRatio;
  }

  @override
  void cancelPointer(int pointer) {
    if (_pendingPointerEvents.isEmpty && !locked) {
      scheduleMicrotask(_flushPointerEventQueue);
    }
    _pendingPointerEvents.addFirst(PointerCancelEvent(pointer: pointer));
  }

  void _flushPointerEventQueue() {
    assert(!locked);
    while (_pendingPointerEvents.isNotEmpty) {
      _handlePointerEvent(_pendingPointerEvents.removeFirst());
    }
  }

  final Map<int, HitTestResult> _hitTests = <int, HitTestResult>{};

  void _handlePointerEvent(PointerEvent event) {
    assert(!locked);
    HitTestResult result;
    if (event is PointerDownEvent) {
      assert(!_hitTests.containsKey(event.pointer));
      result = HitTestResult();
      hitTestInView(
          result, event.position, platformDispatcher.implicitView!.viewId);
      _hitTests[event.pointer] = result;
      assert(() {
        if (debugPrintHitTestResults) debugPrint('$event: $result');
        return true;
      }());
    } else if (event is PointerUpEvent || event is PointerCancelEvent) {
      result = _hitTests.remove(event.pointer)!;
    } else if (event.down) {
      result = _hitTests[event.pointer]!;
    } else {
      return; // We currently ignore add, remove, and hover move events.
    }
    //if (result != null)
    dispatchEvent(event, result);
  }
}
